package cn.easyutil.deploy.util;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.util.*;

public class XmlUtil {

	private static ThreadLocal<Object> xmlVal = new ThreadLocal<Object>();
	private static final int CHECK = 1;
	private static final int UPDATE = 2;
	private static final int DELETE = 3;
	
	//xml根目录名称
	private String header = "xml";
	//xml根目录属性
	private String attribute;
	//xml实体
	private StringBuffer body = new StringBuffer();
	
	public XmlUtil(String header, String attribute){
		this.header = header;
		this.attribute = attribute;
	}
	
	public XmlUtil(String header, String attribute, Map<String, Object> map){
		this.header = header;
		this.attribute = attribute;
		mapToXMLTest2(map, this.body);
	}
	
	public XmlUtil setVal(Map<String, Object> map){
		mapToXMLTest2(map, this.body);
		return this;
	}
	
	public String getXml(){
		return "<"+this.header+" "+this.attribute+">"+this.body.toString()+"</"+this.header+">";
	}
	
	/**
	 * xml转map,支持多级转换
	 * @param text 要转换的xml
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, Object> xmlToMap(String text) {
		Document doc = null;
		try {
			doc = DocumentHelper.parseText(text);
		} catch (DocumentException e1) {
			throw new RuntimeException(e1);
		}
		Map<String, Object> map = new HashMap<String, Object>();
		if (doc == null)
			return map;
		Element root = doc.getRootElement();
		for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
			Element e = (Element) iterator.next();
			List list = e.elements();
			if (list.size() > 0) {
				map.put(e.getName(), Dom2Map(e));
			} else
				map.put(e.getName(), e.getText());
		}
		return map;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static Map Dom2Map(Element e) {
		Map map = new HashMap();
		List list = e.elements();
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				Element iter = (Element) list.get(i);
				List mapList = new ArrayList();

				if (iter.elements().size() > 0) {
					Map m = Dom2Map(iter);
					if (map.get(iter.getName()) != null) {
						Object obj = map.get(iter.getName());
						if (!obj.getClass().getName().equals("java.util.ArrayList")) {
							mapList = new ArrayList();
							mapList.add(obj);
							mapList.add(m);
						}
						if (obj.getClass().getName().equals("java.util.ArrayList")) {
							mapList = (List) obj;
							mapList.add(m);
						}
						map.put(iter.getName(), mapList);
					} else
						map.put(iter.getName(), m);
				} else {
					if (map.get(iter.getName()) != null) {
						Object obj = map.get(iter.getName());
						if (!obj.getClass().getName().equals("java.util.ArrayList")) {
							mapList = new ArrayList();
							mapList.add(obj);
							mapList.add(iter.getText());
						}
						if (obj.getClass().getName().equals("java.util.ArrayList")) {
							mapList = (List) obj;
							mapList.add(iter.getText());
						}
						map.put(iter.getName(), mapList);
					} else
						map.put(iter.getName(), iter.getText());
				}
			}
		} else
			map.put(e.getName(), e.getText());
		return map;
	}
	
	/**
	 * 将xml里的某个值取出
	 * @param xml 
	 * @return
	 */
	public static Object getVal(String xml,String key){
		Map<String, Object> map = xmlToMap(xml);
		checkVal(map, key,null,CHECK);
		Object val = xmlVal.get();
		xmlVal.remove();
		return val;
	}
	
	/**
	 * 往xml里面追加一行数据
	 * @param xml	原xml
	 * @param key	追加的key
	 * @param val	追加的val
	 * @return	追加后的xml
	 */
	public static String setVal(String xml,String key,Object val){
		String root = xml.substring(xml.indexOf("<")+1,xml.indexOf(">"));
		if(root.startsWith(" ")){
			root = root.replaceFirst(" ", "");
		}
		String header = root;
		String attribute = "";
		if(root.contains(" ")){
			int index = root.indexOf(" ");
			header = root.substring(0, index);
			attribute = root.substring(index).replace(" ", "");
		}
		Map<String, Object> map = xmlToMap(xml);
		map.put(key, val);
		return mapToXml(map,header,attribute);
	}

	/**
	 * 修改xml中key对应的val
	 * @param xml	原xml
	 * @param root	根目录
	 * @param key	要修改的key
	 * @param val	要替换的val
	 * @return	修改后的xml
	 */
	public static String updateVal(String xml,String key,Object val){
		String root = xml.substring(xml.indexOf("<")+1,xml.indexOf(">"));
		if(root.startsWith(" ")){
			root = root.replaceFirst(" ", "");
		}
		String header = root;
		String attribute = "";
		if(root.contains(" ")){
			int index = root.indexOf(" ");
			header = root.substring(0, index);
			attribute = root.substring(index).replace(" ", "");
		}
		Map<String, Object> map = xmlToMap(xml);
		checkVal(map, key,val,UPDATE);
		return mapToXml(map,header,attribute);
	}
	
	/**
	 * 删除xml中的key对应的数据
	 * @param xml	原xml
	 * @param key	要删除的key
	 * @return	删除后的xml
	 */
	public static String delVal(String xml,String key){
		String root = xml.substring(xml.indexOf("<")+1,xml.indexOf(">"));
		if(root.startsWith(" ")){
			root = root.replaceFirst(" ", "");
		}
		String header = root;
		String attribute = "";
		if(root.contains(" ")){
			int index = root.indexOf(" ");
			header = root.substring(0, index);
			attribute = root.substring(index).replace(" ", "");
		}
		Map<String, Object> map = xmlToMap(xml);
		checkVal(map, key,null,DELETE);
		return mapToXml(map,header,attribute);
	}
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void checkVal(Map map,String key,Object val,int type){
		Set set = map.keySet();
		for (Object object : set) {
			if(map.get(object) instanceof Map){
				Map obj = (Map) map.get(object);
				checkVal(obj,key,val,type);
			}
			if(object.equals(key)){
				if(type == CHECK){
					xmlVal.set(map.get(object));
					return;
				}else if(type == UPDATE){
					map.put(object, val);
					return;
				}else if(type == DELETE){
					map.remove(object);
					return;
				}
				
			}
		}
	}
	/**
	 * map转xml,支持多级转换
	 * @param map
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String mapToXml(Map map){
		String root = "xml";
		return mapToXml(map, root,null);
	}
	/**
	 * map转xml,支持多级转换
	 * @param map	要转换的map
	 * @param root	根目录名称
	 * @param attribute	根目录属性
	 * @return
	 */
	public static String mapToXml(@SuppressWarnings("rawtypes") Map map,String root,String attribute){
		StringBuffer bu = new StringBuffer();
		mapToXMLTest2(map, bu);
		root = root.replace(" ", "");
		attribute = " "+attribute;
		return "<"+root+attribute+">"+bu.toString()+"</"+root+">";
	}
	@SuppressWarnings("rawtypes")
	private static void mapToXMLTest2(Map map, StringBuffer sb) {
		Set set = map.keySet();
		for (Iterator it = set.iterator(); it.hasNext();) {
			String key = (String) it.next();
			Object value = map.get(key);
			if (null == value){
				value = "";
			}
			if (value instanceof List) {
				ArrayList list = (ArrayList) map.get(key);
				sb.append("<" + key + "><![CDATA[");
				for (int i = 0; i < list.size(); i++) {
					if(list.get(i) instanceof Map){
						HashMap hm = (HashMap) list.get(i);
						mapToXMLTest2(hm, sb);
					}else{
						sb.append(list.get(i)+",");
					}
				}
				sb.delete(sb.length()-1, sb.length());
				sb.append("]]>");
				sb.append("</" + key + ">");
				
			}else {
				if (value instanceof Map) {
					sb.append("<" + key + ">");
					mapToXMLTest2((Map) value, sb);
					sb.append("</" + key + ">");
				}else {
					sb.append("<" + key + "><![CDATA[" + value + "]]></" + key + ">");
				}
			}
				
		}
	}
	
	public static void main(String[] args) {
		Map<String, Object> map = new HashMap<String, Object>();
		Map<String, Object> val = new HashMap<String, Object>();
		val.put("loc", "http://liuxianan.com");
		val.put("lastmod", new Date());
		val.put("changefreq", "hourly");
		val.put("priority", "0.5");
		map.put("url", val);
		String xml = mapToXml(map,"urlset","xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"");
		xml = setVal(xml, "url", val);
		System.out.println(xml);
		
	}
}
